package com.wiretrack.circuit;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;

import javax.swing.JPanel;
import javax.swing.Timer;

import org.apache.log4j.Logger;

public class CountdownActionListener implements ActionListener
{
	private static final int ONE_SECOND = 1000;
	private static Logger log = Logger.getLogger(CountdownActionListener.class.getName());
	private static Color TIMER_GO_COLOR = new Color(0, 128, 0);
	private static SimpleDateFormat timeFormat = new SimpleDateFormat("m:ss");

	private Calendar calendar = Calendar.getInstance();
	private boolean isDone = false;
	private Round round;
	private Configuration config;
	private Label nameLabel;
	private Label descriptionLabel;
	private Label nextLabel;
	private Progress progressBar;
	private int currentRoundNumber;
	private static int totalProgress = 0;
	private Label timeLabel;
	private ScreenFlasher colorChanger;
	private JPanel flasherPanelOne;
	private JPanel flasherPanelTwo;
	private boolean flashesWereRun;
	private int textShowCount = 0;
	private double progressIncrementSize;

	public CountdownActionListener(Round rnd, Configuration configuration, Label time, Label name, Label description,
			Label next, Progress progress, JPanel panel1, JPanel panel2)
	{
		round = rnd;
		config = configuration;

		calendar.setTimeInMillis(round.length * ONE_SECOND);

		timeLabel = time;
		nameLabel = name;
		descriptionLabel = description;
		nextLabel = next;
		progressBar = progress;
		if(totalProgress == 0)
			totalProgress = 100 / config.roundrefs.roundrefs.size();
		flasherPanelOne = panel1;
		flasherPanelTwo = panel2;
		progressIncrementSize = (double)(100.0/config.roundrefs.roundrefs.size()*1.0);
	}

	public boolean isDone()
	{
		return isDone;
	}

	@Override
	public void actionPerformed(ActionEvent e)
	{
		playSoundIfItsTimeTo();

		calendar.add(Calendar.SECOND, -1);

		if ( calendar.get(Calendar.MINUTE) == 0 && calendar.get(Calendar.SECOND) == 0 )
		{
			log.debug("stopping timer...");
			((Timer) e.getSource()).stop();
			updateProgress();
			isDone = true;
		}

		updateUIcomponents();
	}

	private void updateUIcomponents()
	{
		flashesWereRun = false;
		String textId = null;

		if ( round.texts != null && round.texts.size() > 0 )
		{
			for (Text text : round.texts)
			{
				if ( isCurrentTimeEqualTo(text.showAt) )
				{
					TimerText tt = config.getTimerText(text.refid);
					textId = tt.id;
					
					textShowCount = tt.lengthInMS;
					log.debug("text to show=" + text.refid + " showcount=" + textShowCount + " show at=" + text.showAt + " current time: " + calendar.getTimeInMillis());
				}

				//which one not taken into account?
				if ( isCurrentTimeLessThanOrEqualTo(text.showAt) && textShowCount > 0 && textId != null && textId.length() > 0 )
				{
					--textShowCount;
					log.debug("show count=" + textShowCount + " textId=" + textId);
					TimerText tt = config.getTimerText(textId);
					timeLabel.setText(tt.text);
				}
				else
				{
					timeLabel.setText(timeFormat.format(calendar.getTime()));
					textShowCount = 0;
				}
			}
		}
		else
		{
			if ( textShowCount <= 0 )
			{
				timeLabel.setText(timeFormat.format(calendar.getTime()));
			}
		}

		updateTimerLabelColorIfRestOrEndOfRound();

		nameLabel.setText(round.name);
		descriptionLabel.setText(round.description);

		updateNextLabelColorAndText();
		runScreenFlashers();
	}

	private void runScreenFlashers()
	{
		if ( round != null && round.flashers != null )
		{
			List<Flash> flashes = round.flashers;

			for (Flash flash : flashes)
			{
				if ( isCurrentTimeEqualTo(flash.flashAt) && !flashesWereRun )
				{
					ScreenFlash sf = config.getScreenFlash(flash.refid);

					if ( sf != null )
					{
						ScreenFlasher flasher = new ScreenFlasher(sf, flasherPanelOne, flasherPanelTwo,
								config.getBackgroundColor());
						flasher.start();
						flashesWereRun = true;
					}
				}
			}
		}
	}

	private boolean isCurrentTimeEqualTo(int timeInMillis)
	{
		if ( calendar.getTimeInMillis() == timeInMillis * ONE_SECOND )
			return true;
		else
			return false;
	}

	private boolean isCurrentTimeLessThanOrEqualTo(int timeInMillis)
	{
		if ( calendar.getTimeInMillis() <= timeInMillis * ONE_SECOND )
			return true;
		else
			return false;
	}

	private void updateProgress()
	{
		totalProgress = (int) (totalProgress + progressIncrementSize);
		log.debug("total progress: " + totalProgress);
		
		if ( currentRoundNumber + 1 == config.rounds.rounds.size() )
		{
			progressBar.setValue(100);
		}
		else
		{
			progressBar.setValue(totalProgress);
		}
	}

	private void updateNextLabelColorAndText()
	{
		if ( calendar.getTimeInMillis() <= config.nextalerttime * ONE_SECOND )
		{
			nextLabel.setForeground(Color.RED);
			descriptionLabel.setForeground(Color.GRAY);
		}
		else
		{
			nextLabel.setForeground(Color.GRAY);
			descriptionLabel.setForeground(Color.BLACK);
		}

		Round nextRound = config.getRoundAt(currentRoundNumber + 1);
		if ( nextRound != null )
		{
			nextLabel.setText(config.nextPrefix + nextRound.name + " - " + nextRound.description);
		}
		else
		// is done!
		{
			log.debug("Is last round!!!");
			if ( calendar.getTimeInMillis() <= config.nextalerttime * ONE_SECOND )
			{
				nextLabel.setForeground(Color.RED);
				nextLabel.setText(config.donemessage);
			}
			else
			{
				nextLabel.setText("last round!");
			}
		}
	}

	private void updateTimerLabelColorIfRestOrEndOfRound()
	{
		if ( round.isRest )
		{
			timeLabel.setForeground(Color.RED);
		}
		else if ( calendar.getTimeInMillis() <= config.endofroundwarning * ONE_SECOND )
		{
			timeLabel.setForeground(Color.ORANGE);

			// only cycle colors one time
			if ( colorChanger != null && calendar.getTimeInMillis() == config.endofroundwarning * ONE_SECOND )
			{
				ScreenFlasher bc = new ScreenFlasher(colorChanger);
				bc.start();
			}
		}
		else
		{
			timeLabel.setForeground(TIMER_GO_COLOR);
		}
	}

	private void playSoundIfItsTimeTo()
	{
		// log.debug("Cal time in ms: " + calendar.getTimeInMillis());

		if ( round.sounds != null && round.sounds.size() > 0 )
		{
			for (Sound sound : round.sounds)
			{
				if ( calendar.getTimeInMillis() == sound.playAt * ONE_SECOND )
				{
					String toPlay = sound.getResolvedRef(config);

					if ( toPlay != null && toPlay.length() > 0 )
					{
						log.debug("Sound to play: " + toPlay + " at defined time: " + ONE_SECOND * sound.playAt
								+ " timer time: " + calendar.getTimeInMillis());
						Utils.playSound(config, toPlay);
					}
				}
			}

		}
	}

	public void setCurrentRoundNumber(int roundCount)
	{
		currentRoundNumber = roundCount;
		log.debug("Current round number: " + currentRoundNumber + " Name: " + round.name);
	}
}
